home *** CD-ROM | disk | FTP | other *** search
Visual Basic class definition | 2001-10-08 | 17.7 KB | 455 lines |
- VERSION 1.0 CLASS
- BEGIN
- MultiUse = -1 'True
- Persistable = 0 'NotPersistable
- DataBindingBehavior = 0 'vbNone
- DataSourceBehavior = 0 'vbNone
- MTSTransactionMode = 0 'NotAnMTSObject
- END
- Attribute VB_Name = "cPuck"
- Attribute VB_GlobalNameSpace = False
- Attribute VB_Creatable = True
- Attribute VB_PredeclaredId = False
- Attribute VB_Exposed = False
- Option Explicit
-
- Private Const mnMaxSpinSpeed As Single = 0.9
- 'Here we will encapsulate all of the code needed for the puck
- 'Local variables for the properties of the puck
- Private moPosition As D3DVECTOR 'Current position of the puck
- Private moVelocity As D3DVECTOR 'Current velocity of the puck
- Private moLastPosition As D3DVECTOR 'Last position of the puck
-
- Public Spinning As Boolean 'Is the puck currently spinning?
- Public MaximumPuckVelocity As Single
-
- Private mnSpinDir As Single 'Direction of the pucks spinning
- Private mlPuckTime As Long 'Last time the puck was updated
- Private mnPuckSpin As Single
-
- Private moPuck As CD3DFrame 'D3D Mesh for the puck
- 'Default spin speed
- Private mnDefaultSpin As Single
-
- 'Position property
- Public Property Let Position(oPos As D3DVECTOR)
- moPosition = oPos
- End Property
-
- Public Property Get Position() As D3DVECTOR
- Position = moPosition
- End Property
-
- 'Velocity property
- Public Property Let Velocity(oVel As D3DVECTOR)
- moVelocity = oVel
- 'Update the velocity, but make sure it isn't too high
- EnsurePuckVelocityIsBelowMax
- End Property
-
- Public Property Get Velocity() As D3DVECTOR
- Velocity = moVelocity
- End Property
-
- 'LastPosition prop
- Public Property Let LastPosition(oLastPos As D3DVECTOR)
- moLastPosition = oLastPos
- End Property
-
- Public Property Get LastPosition() As D3DVECTOR
- LastPosition = moLastPosition
- End Property
-
- 'Different methods from the puck.
- Public Sub Init(ByVal sMedia As String, sFile As String)
- Set moPuck = D3DUtil_LoadFromFile(AddDirSep(sMedia) & sFile, Nothing, Nothing)
- End Sub
-
- Public Sub UpdatePosition()
- Dim RealVelocity As D3DVECTOR
-
- 'Here we will update the position of the puck
- 'and move it based on the velocity assigned.
- If mlPuckTime = 0 Then mlPuckTime = timeGetTime
- 'First calculate the 'real' velocity (based on the time)
- RealVelocity.X = ((timeGetTime - mlPuckTime) / 100) * moVelocity.X
- RealVelocity.Y = ((timeGetTime - mlPuckTime) / 100) * moVelocity.Y
- RealVelocity.z = ((timeGetTime - mlPuckTime) / 100) * moVelocity.z
- 'Let's save our current position
- moLastPosition = moPosition
-
- moPosition.X = moPosition.X + RealVelocity.X
- moPosition.Y = moPosition.Y + RealVelocity.Y
- moPosition.z = moPosition.z + RealVelocity.z
-
- If Spinning Then
- 'Update Puck Spin
- mnPuckSpin = mnPuckSpin + ((((timeGetTime - mlPuckTime) / 100) * mnDefaultSpin) * mnSpinDir)
- If mnPuckSpin > 2 * g_pi Then mnPuckSpin = 0
- End If
-
- mlPuckTime = timeGetTime
- End Sub
-
- Public Sub Render(dev As Direct3DDevice8)
- Dim matRot As D3DMATRIX, matTrans As D3DMATRIX
- Dim matPuck As D3DMATRIX
-
- D3DXMatrixRotationAxis matRot, vec3(0, 1, 0), mnPuckSpin
- D3DXMatrixTranslation matTrans, moPosition.X, moPosition.Y, moPosition.z
- D3DXMatrixMultiply matPuck, matRot, matTrans
-
- moPuck.SetMatrix matPuck
- moPuck.Render dev
-
- End Sub
-
- Public Sub LaunchPuck()
- Randomize
- DefaultStartPosition
- Do While (D3DXVec3Length(moVelocity) < (MaximumPuckVelocity / 4)) And (Abs(moVelocity.z) < 0.2) 'Make sure there is *some* z movement
- moVelocity.z = Rnd * (MaximumPuckVelocity / 3)
- moVelocity.X = Rnd * (MaximumPuckVelocity / 3)
- If Rnd > 0.5 Then moVelocity.X = moVelocity.X * -1
- If Rnd < 0.5 Then moVelocity.z = moVelocity.z * -1
- Loop
- End Sub
-
- Public Sub DefaultStartPosition()
- moPosition = vec3(0, 2.5, 0)
- moVelocity = vec3(0, 0, 0)
- moLastPosition = vec3(0, 0, 0)
- End Sub
-
- Public Sub ChangePuckVelocity(oPaddle As cPaddle, oAudio As cAudio, Optional ByVal fIgnoreMax As Boolean = False)
-
- Dim vDir As D3DVECTOR
- Dim a As Single, b As Single, c As Single
- Dim t0 As Single, t1 As Single
- Dim vIntersect As D3DVECTOR, vIntersectHigh As D3DVECTOR
- Dim oPlane As D3DPLANE, matReflect As D3DMATRIX
- Dim oPoint As D3DVECTOR, vNewVelDir As D3DVECTOR
- Dim vPuck As D3DVECTOR, tSmall As Single
- Dim nVelocity As Single, nVelocityPaddle As Single
- Dim vNewVelPad As D3DVECTOR
-
- 'We hit with the paddle, randomly change the spin direction
- UpdatePuckSpin
- glPaddleCollideTime = timeGetTime
- 'gfRecentlyHitPaddle = True
- 'Notify the user that the puck hit the paddle by playing a sound
- If Not (oAudio Is Nothing) Then oAudio.PlayHitSound
- 'Let's store the original velocity
- nVelocity = D3DXVec3Length(moVelocity)
- nVelocityPaddle = D3DXVec3Length(oPaddle.Velocity) * gnPaddleMass
- 'First we need to find the intersection point
- 'To do that we first need to solve for t:
- 'x = Dxt + x0
- 'z = Dzt + z0
- D3DXVec3Subtract vPuck, moPosition, oPaddle.Position
- D3DXVec3Normalize vDir, moVelocity
- a = 1 ' (vDir.x ^ 2) + (vDir.z ^ 2) will always be one since the vector is normalized
- b = (2 * vPuck.X * vDir.X) + (2 * vPuck.z * vDir.z)
- c = ((vPuck.X ^ 2) + (vPuck.z ^ 2) - ((gnPaddleRadius + gnPuckRadius) ^ 2))
- 't = (-b â–’ SQR(bâ–“-4ac))/2a
- If (b ^ 2) - (4 * a * c) > 0 Then
- t0 = (-b + Sqr((b ^ 2) - (4 * a * c))) / (2 * a)
- t1 = (-b - Sqr((b ^ 2) - (4 * a * c))) / (2 * a)
- Else 'We shouldn't hit this case, but just in case.
- t0 = 0
- t1 = 0
- End If
-
- Dim vInt1 As D3DVECTOR, vInt2 As D3DVECTOR
- Dim vDifInt1 As D3DVECTOR, vDifInt2 As D3DVECTOR
- 'Find both possible intersection points
- vInt1.X = (vDir.X * t0) + vPuck.X: vInt1.z = (vDir.z * t0) + vPuck.z
- vInt2.X = (vDir.X * t1) + vPuck.X: vInt2.z = (vDir.z * t1) + vPuck.z
- 'Find the difference from the starting location
- D3DXVec3Subtract vDifInt1, oPaddle.Position, vInt1
- D3DXVec3Subtract vDifInt2, oPaddle.Position, vInt2
-
- 'Find the smallest t
- 'If t0 > t1 Then
- If D3DXVec3Length(vDifInt1) < D3DXVec3Length(vDifInt2) Then
- tSmall = t1
- Else
- tSmall = t0
- End If
- 'Let's get the intersected point
- vIntersect.X = (vDir.X * tSmall) + vPuck.X
- vIntersect.z = (vDir.z * tSmall) + vPuck.z
-
- 'Create a new vector with an enormously high Y field to create our reflection plane
- vIntersectHigh = vIntersect
- vIntersectHigh.Y = 500
- 'Let's create a plane from this point
- D3DXPlaneFromPoints oPlane, vec3(0, 0, 0), vIntersect, vIntersectHigh
-
- 'Now we can create a reflection matrix based on this plane
- D3DXMatrixReflect matReflect, oPlane
- 'Create a new point that is reflected
- D3DXVec3TransformCoord oPoint, vPuck, matReflect
- D3DXVec3Subtract vNewVelDir, oPoint, vIntersect
- 'Normalize the vector
- D3DXVec3Normalize vNewVelDir, vNewVelDir
- vNewVelDir.X = -vNewVelDir.X
- vNewVelDir.z = -vNewVelDir.z
- D3DXVec3Scale moVelocity, vNewVelDir, nVelocity
- If nVelocityPaddle > 0 Then 'The paddle is moving, add it's velocity
- 'Now let's add the velocity of the paddle to our resulting velocity
- D3DXVec3Normalize vNewVelPad, oPaddle.Velocity
- D3DXVec3Scale vNewVelPad, vNewVelPad, nVelocityPaddle
- D3DXVec3Add moVelocity, moVelocity, vNewVelPad
- End If
- Debug.Print "Old Velocity:"; nVelocity; " - New Velocity:"; D3DXVec3Length(moVelocity)
- 'If we are limiting the velocity to it's maximum (most times), do so
- If Not fIgnoreMax Then EnsurePuckVelocityIsBelowMax
- End Sub
-
- Public Sub CheckCollisions(oPaddle() As cPaddle, Optional oAudio As cAudio = Nothing)
- 'First we should check to see if we are scoring in this frame.
- Dim nDistance As Single
- Dim lCount As Long, fCollided As Boolean
- Dim lCollided As Long, nCollideDist As Single
-
- If gfScored Then Exit Sub
- 'Check to see if the puck has collided with any of the walls
- 'We could do an exhaustive check to see if any of the polygons collide, but since the table
- 'is static, in the name of faster calculations, we will use a group of constants defining the
- 'edges of the walls. We will check those instead.
-
- 'If the puck does hit one of the walls, we can easily calculate it's new direction by simply reversing
- 'it's velocity (of that vector). If we want to be even more accurate we can lower the velocity by a small amount as well
-
- 'The left and right walls are bound to the X axis
- If moPosition.X > (gnSideLeftWallEdge - (gnPuckRadius)) Then
- 'We hit the wall
- 'Reverse the velocity of the X axis
- moVelocity = vec3((moVelocity.X * -1) * gnVelocityDamp, 0, moVelocity.z)
- moPosition = vec3((gnSideLeftWallEdge - (gnPuckRadius)), moPosition.Y, moPosition.z)
- If Not (oAudio Is Nothing) Then oAudio.PlayBankSound
- gfRecentlyHitPaddle = False
- ElseIf moPosition.X < (gnSideRightWallEdge + (gnPuckRadius)) Then
- 'We hit the wall
- moVelocity = vec3((moVelocity.X * -1) * gnVelocityDamp, 0, moVelocity.z)
- moPosition = vec3((gnSideRightWallEdge + (gnPuckRadius)), moPosition.Y, moPosition.z)
- If Not (oAudio Is Nothing) Then oAudio.PlayBankSound
- gfRecentlyHitPaddle = False
- End If
-
- 'The front and rear walls are count to the Z axis
- If moPosition.z > (gnNearWallEdge - (gnPuckRadius)) Then
- 'Only reverse the velocity if we hit the sides of the 'scoring area'
- If (moPosition.X > (gnScoringEdgeLeft - (gnPuckRadius))) Or (moPosition.X < (gnScoringEdgeRight + (gnPuckRadius))) Then
- 'We hit the wall
- 'Reverse the velocity of the Z axis
- moVelocity = vec3(moVelocity.X, 0, (moVelocity.z * -1) * gnVelocityDamp)
- moPosition = vec3(moPosition.X, moPosition.Y, gnNearWallEdge - (gnPuckRadius))
- If Not (oAudio Is Nothing) Then oAudio.PlayBankSound
- gfRecentlyHitPaddle = False
- End If
- ElseIf moPosition.z < (gnFarWallEdge + (gnPuckRadius)) Then
- If (moPosition.X > (gnScoringEdgeLeft - (gnPuckRadius))) Or (moPosition.X < (gnScoringEdgeRight - (gnPuckRadius))) Then
- 'We hit the wall
- moVelocity = vec3(moVelocity.X, 0, (moVelocity.z * -1) * gnVelocityDamp)
- moPosition = vec3(moPosition.X, moPosition.Y, gnFarWallEdge + (gnPuckRadius))
- If Not (oAudio Is Nothing) Then oAudio.PlayBankSound
- gfRecentlyHitPaddle = False
- End If
- End If
-
- 'Next we should check to see if the puck has collided with either of the paddles
- 'We will use a simple formula to determine if the puck has collided with one of the
- 'paddles. Simply put if the distance between the center of the puck, and the center
- 'of the paddle in question is greater than the radius of the puck + the radius of the
- 'paddle, they haven't collided
- Dim vecDif As D3DVECTOR
-
- If ((timeGetTime - glPaddleCollideTime) > glMinDelayPaddleHit) Or (Not gfRecentlyHitPaddle) Then
- gfRecentlyHitPaddle = False
- For lCount = 0 To 1 'Both paddles
- 'We only check the X/Z coords because in this demo the puck will never leave the table
- 'so it will maintain a constant Y coord.
- D3DXVec3Subtract vecDif, moPosition, oPaddle(lCount).Position
- nDistance = D3DXVec3Length(vecDif)
- If nDistance < (gnPaddleRadius + gnPuckRadius) Then 'They have collided
- nCollideDist = nDistance
- lCollided = lCount
- fCollided = True
- If gfMultiplayer Then
- 'Let each client handle it's own collision detection
- 'in a multiplayer game. This balances the load between
- 'the host machine, and the client machine and gives the
- 'most realistic playing feel.
- If glMyPaddleID = lCount Then 'We collided with our paddle
- ChangePuckVelocity oPaddle(lCount), oAudio
- SendPuck
- SendCollidePaddle
- End If
- Else
- ChangePuckVelocity oPaddle(lCount), oAudio
- End If
- End If
- Next
- End If
- ' Make sure we aren't colliding anymore
- If fCollided Then EnsurePuckIsNotInPaddle nCollideDist, oPaddle(lCollided)
- 'Lastly we should check if we have scored (on either side)
- If gfMultiplayer And (Not gfHost) Then Exit Sub 'Only the host should check for scoring
- If moPosition.z > (gnNearWallEdge) Then
- 'We scored!
- goPuck.DropPuckIntoScoringPosition goAudio
- ElseIf moPosition.z < (gnFarWallEdge) Then
- 'We scored!
- goPuck.DropPuckIntoScoringPosition goAudio
- End If
- End Sub
-
- Public Sub EnsurePuckIsNotInPaddle(ByVal nDistance As Single, oPaddle As cPaddle, Optional ByVal fSentPaddle As Boolean = False)
- 'Move the paddle back out so it's not hitting the puck
- Dim vDir As D3DVECTOR, vScale As D3DVECTOR, vPaddleVel As D3DVECTOR
-
- If fSentPaddle Then
- D3DXVec3Subtract vPaddleVel, oPaddle.LastPosition, oPaddle.Position
- 'Get the direction vector by normalizing the paddle's velocity
- D3DXVec3Normalize vDir, vPaddleVel
- Else
- 'Get the direction vector by normalizing the pucks velocity
- D3DXVec3Normalize vDir, moVelocity
- End If
- 'Scale the vector, just enough to get it out of the paddle
- D3DXVec3Scale vScale, vDir, (gnPuckRadius + gnPaddleRadius) - nDistance
- 'Move the puck to it's new location
- D3DXVec3Add moPosition, moPosition, vScale
- 'Now, let's increase the pucks velocity that much as well..
- If fSentPaddle Then D3DXVec3Add moVelocity, moVelocity, vScale
- End Sub
-
- Private Sub UpdatePuckSpin()
- Randomize
- If Rnd > 0.5 Then
- mnSpinDir = mnSpinDir * -1
- 'Update the spin, change speed from 75%-125% of current speed..
- mnDefaultSpin = (Rnd * (mnSpinDir * 0.75)) + (mnSpinDir * 0.5)
- If Abs(mnDefaultSpin) > mnMaxSpinSpeed Then
- mnDefaultSpin = mnMaxSpinSpeed * (Abs(mnDefaultSpin) \ mnDefaultSpin)
- End If
- End If
- End Sub
-
- Public Sub CleanupFrame()
- moPuck.Destroy
- Set moPuck = Nothing
- End Sub
-
- Public Sub DropPuckIntoScoringPosition(oAudio As cAudio, Optional ByVal fFromReceive As Boolean = False)
-
- gfScored = True
- glTimeCompPaddle = 0
- If Not gfMultiplayer Then
- With goPaddle(1).Velocity
- .X = 0: .z = 0
- End With
- End If
- glTimePuckScored = timeGetTime
- oAudio.PlayScoreSound
- If gfMultiplayer Then
- If Not gfHost And Not fFromReceive Then Exit Sub
- End If
- 'First stop the velocity
- moVelocity = vec3(0, 0, 0)
-
- With moPosition
- 'Now position the puck
- If .z < 0 Then
- gPlayer(1).Score = gPlayer(1).Score + 1
- .z = gnFarWallEdge - 1.2
- ElseIf .z > 0 Then
- .z = gnNearWallEdge + 1.2
- gPlayer(0).Score = gPlayer(0).Score + 1
- End If
- If Abs(.X) > gnScoringEdgeLeft / 3 Then
- If Abs(.X) <> .X Then
- .X = gnScoringEdgeRight / 3
- Else
- .X = gnScoringEdgeLeft / 3
- End If
- End If
- .Y = gnPuckScored
- End With
-
- Spinning = False
- 'If we are the host, notify everyone that we've scored
- If gfMultiplayer Then NotifyPlayersWeScored
-
- End Sub
-
- Public Function FadeMesh(FadeInterval As Single) As Boolean
- Dim lNumMaterial As Long
- Dim lCount As Long
- Dim oMaterial As D3DMATERIAL8
- Dim fDoneFading As Boolean
- Dim oMesh As CD3DMesh
- Dim nInternalInterval As Single
- Static lFadeTime As Long
-
- nInternalInterval = FadeInterval
- If lFadeTime = 0 Then
- lFadeTime = timeGetTime
- Exit Function 'We'll do the fade next render pass
- End If
- nInternalInterval = (((timeGetTime - lFadeTime) / 1000000) * nInternalInterval)
-
- Set oMesh = moPuck.FindChildObject("puck", 0)
- fDoneFading = True
- lNumMaterial = oMesh.GetMaterialCount
- For lCount = 0 To lNumMaterial - 1
- oMaterial = oMesh.GetMaterial(lCount)
- If nInternalInterval > 0 And oMaterial.diffuse.a <= 1 Then
- oMaterial.diffuse.a = oMaterial.diffuse.a + nInternalInterval
- fDoneFading = False
- ElseIf nInternalInterval < 0 And oMaterial.diffuse.a >= -1 Then
- oMaterial.diffuse.a = oMaterial.diffuse.a + nInternalInterval
- fDoneFading = False
- End If
- oMesh.SetMaterial lCount, oMaterial
- Next
- FadeMesh = fDoneFading
- End Function
-
- Public Sub PauseSystem(ByVal fPause As Boolean)
- If Not fPause Then
- mlPuckTime = timeGetTime
- End If
- End Sub
-
- '************
- 'Private functions that the public subs here will call, but the main application doesn't need to know about
-
- Private Sub EnsurePuckVelocityIsBelowMax()
- Dim VelVec As D3DVECTOR
- 'Let's make sure the puck's velocity isn't above the max,
- 'and if it is, lower it to the max velocity
- If D3DXVec3Length(moVelocity) > MaximumPuckVelocity Then
- 'Yup, lower the velocity to the max
- Dim vNrm As D3DVECTOR
-
- D3DXVec3Normalize vNrm, moVelocity
- D3DXVec3Scale VelVec, vNrm, MaximumPuckVelocity
- moVelocity = VelVec
- End If
- End Sub
-
- Private Sub Class_Initialize()
- mnSpinDir = 1
- mnDefaultSpin = 0.15
- Set moPuck = Nothing
- DefaultStartPosition
- End Sub
-
- Private Sub Class_Terminate()
- If Not moPuck Is Nothing Then moPuck.Destroy
- Set moPuck = Nothing
- End Sub
-